package com.qingzhou.web.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.format.DateTimeFormat;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.solon.service.impl.ServiceImpl;
import com.qingzhou.common.utils.SecurityUtil;
import com.qingzhou.system.service.ISysDictDataService;
import com.qingzhou.system.service.ISysPostService;
import com.qingzhou.web.repository.dao.DataCheckLogDao;
import com.qingzhou.web.repository.entity.*;
import com.qingzhou.web.repository.mapper.DataCheckLogMapper;
import com.qingzhou.web.service.DataCheckLogService;
import com.qingzhou.web.service.EdcConstants;
import com.qingzhou.web.service.impl.convert.*;
import com.qingzhou.web.service.impl.params.request.DataCheckLogAddForm;
import com.qingzhou.web.service.impl.params.request.DataCheckLogDetailForm;
import com.qingzhou.web.service.util.DictUtil;
import io.swagger.annotations.ApiModelProperty;
import lombok.SneakyThrows;
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Inject;
import org.noear.solon.core.handle.Context;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

@Component
public class DataCheckLogServiceImpl extends ServiceImpl<DataCheckLogMapper, DataCheckLogEntity> implements DataCheckLogService {
    @Inject
    DataCheckLogDao dataCheckLogDao;
    @Inject
    ISysDictDataService dictDataService;
    @Inject
    ISysPostService sysPostService;
    @SneakyThrows
    @Override
    public int add(DataCheckLogAddForm form) {
        DataCheckLogEntity entity = BeanUtil.copyProperties(form, DataCheckLogEntity.class);
        entity.setTableName(getTableNameByTitle(entity.getTitle()));
        entity.setOperName(SecurityUtil.getLoginUser().getSysUser().getNickName());
        Context ctx = Context.current();
        entity.setOperParam(StrUtil.isNotBlank(ctx.body()) ? ctx.body() : ctx.paramMap().toString());
        entity.setCreateBy(SecurityUtil.getUserName());

        return dataCheckLogDao.add(entity);
    }

    private String getTableNameByTitle(String title) {
        String tableName = "";
        switch (title){
            case EdcConstants.EDC_SURGERY:
                tableName = "edc_surgery";
                break;
            case EdcConstants.EDC_COLLECT:
                tableName = "edc_collect";
                break;
            case EdcConstants.EDC_OMICS_COLLECT:
                tableName = "edc_omics_collect";
                break;
            case EdcConstants.EDC_IMAGING:
                tableName = "edc_imaging";
                break;
            case EdcConstants.EDC_OMICS:
                tableName = "edc_omics";
                break;
            case EdcConstants.EDC_PATIENT:
                tableName = "edc_patient";
                break;
            case EdcConstants.EDC_CHECK_RECORDS:
                tableName = "edc_check_records";
                break;
            case EdcConstants.EDC_PATHOLOGY:
                tableName = "edc_pathology";
                break;
            case EdcConstants.EDC_TREATMENT:
                tableName = "edc_treatment";
                break;
            case EdcConstants.EDC_VISIT:
                tableName = "edc_visit";
                break;
        }
        return tableName;
    }


    @Override
    public Page<DataCheckLogEntity> page(Page<DataCheckLogEntity> page, DataCheckLogEntity entity) {
        String title = entity.getTitle();
        String patientCode = entity.getPatientCode();
        QueryWrapper queryWrapper = QueryWrapper.create();
        if(StrUtil.isNotEmpty(patientCode)){
            List<String> split = StrUtil.split(patientCode.trim(), "\n");
            queryWrapper.in("patient_code",split);
        }
        if(StrUtil.isNotEmpty(title)){
            queryWrapper.eq("title", title);
        }
        return dataCheckLogDao.getMapper().paginate(page, queryWrapper.orderBy("create_time desc"));
    }

    @Override
    public DataCheckLogEntity detail(DataCheckLogDetailForm form) {
        DataCheckLogEntity entity = dataCheckLogDao.getById(form.getId());
        Assert.isTrue(ObjUtil.isNotNull(entity),"数据不见了");
        return entity;
    }

    /**
     * 比较两个实体属性值，返回一个map以有差异的属性名为key，value为一个list分别存obj1,obj2此属性名的值
     * @param obj1 进行属性比较的对象1
     * @param obj2 进行属性比较的对象2
     * @param ignoreArr 选择忽略比较的属性数组
     * @return 属性差异比较结果map
     */
    public static JSONObject diff(Object obj1, Object obj2, String[] ignoreArr) {
        String[] ignoreArrFinal = ArrayUtil.addAll(ignoreArr,new String[]{"updateTime","updateBy"});
        try {
            JSONObject json1 = JSON.parseObject(JSON.toJSONString(obj1));
            JSONObject json2 = JSON.parseObject(JSON.toJSONString(obj2));
            Set<String> keys = json1.keySet();
            JSONObject diffContents = new JSONObject();
            Class<?> clazz = obj1.getClass();

            keys.forEach(key -> {
                // 检查是否在忽略列表中
                if (ignoreArrFinal != null && Arrays.asList(ignoreArrFinal).contains(key)) {
                    return;
                }

                boolean isEq = Objects.equals(json1.get(key), json2.get(key));
                if (!isEq) {
                    // 获取字段上的 ApiModelProperty 注解
                    try {
                        Field field = clazz.getDeclaredField(key);
                        ApiModelProperty apiModelProperty = field.getAnnotation(ApiModelProperty.class);
                        ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class);
                        DateTimeFormat dateTimeFormat = field.getAnnotation(DateTimeFormat.class);
                        DictParent dictParent = field.getAnnotation(DictParent.class);
                        String fieldName = key;
                        if (apiModelProperty != null && !apiModelProperty.value().isEmpty()) {
                            fieldName = apiModelProperty.value();  // 使用注解中的 value 属性作为字段名
                        }else{
                            String baseKey = getByBaseKey(fieldName);
                            if(StrUtil.isNotEmpty(baseKey)){
                                fieldName = baseKey;
                            }
                        }
                        // @ExcelProperty(value = {"基本信息", "检测项目"}, converter = TestItemConverter.class) 判断是否有注解，且converter定义的类在包com.qingzhou.service.impl.convert包下
                        boolean isCustomerConverter= excelProperty!=null && excelProperty.converter().getName().startsWith("com.qingzhou.web.service.impl.convert") && dictParent==null;
                        if(StrUtil.equals("familyHistoryDetails",key)){
                            List<FamilyHistoryDetail> family1 = JSON.parseArray(JSON.toJSONString(json1.get(key)), FamilyHistoryDetail.class);
                            List<FamilyHistoryDetail> family2 = JSON.parseArray(JSON.toJSONString(json2.get(key)), FamilyHistoryDetail.class);
                            FamilyHistoryDetailConverter familyHistoryDetailConverter = new FamilyHistoryDetailConverter();
                            diffContents.put(fieldName, ListUtil.toList(familyHistoryDetailConverter.getConvertString(family1),familyHistoryDetailConverter.getConvertString(family2)));
                        }else if(StrUtil.equals("imgChestTestInfoList",key)){
                            List<ImgTestInfo> img1 = JSON.parseArray(JSON.toJSONString(json1.get(key)), ImgTestInfo.class);
                            List<ImgTestInfo> img2 = JSON.parseArray(JSON.toJSONString(json2.get(key)), ImgTestInfo.class);
                            ImgChestTestInfoConverter converter = new ImgChestTestInfoConverter();
                            diffContents.put(fieldName, ListUtil.toList(converter.getConvertString(img1),converter.getConvertString(img2)));
                        } else if(StrUtil.equals("historyDiseaseDetails",key)){
                            List<HistoryDiseaseDetail> val1 = JSON.parseArray(JSON.toJSONString(json1.get(key)), HistoryDiseaseDetail.class);
                            List<HistoryDiseaseDetail> val2 = JSON.parseArray(JSON.toJSONString(json2.get(key)), HistoryDiseaseDetail.class);
                            HistoryDiseaseDetailConverter converter = new HistoryDiseaseDetailConverter();
                            diffContents.put(fieldName, ListUtil.toList(converter.getConvertString(val1),converter.getConvertString(val2)));
                        } else if(StrUtil.equals("nonGeneticDetails",key)){
                            List<NonGeneticDetail> val1 = JSON.parseArray(JSON.toJSONString(json1.get(key)), NonGeneticDetail.class);
                            List<NonGeneticDetail> val2 = JSON.parseArray(JSON.toJSONString(json2.get(key)), NonGeneticDetail.class);
                            NonGeneticDetailConverter converter = new NonGeneticDetailConverter();
                            diffContents.put(fieldName, ListUtil.toList(converter.getConvertString(val1),converter.getConvertString(val2)));
                        } else if(StrUtil.equals("medicationsHistoryNames",key)){
                            List<String> val1 = JSON.parseArray(JSON.toJSONString(json1.get(key)), String.class);
                            List<String> val2 = JSON.parseArray(JSON.toJSONString(json2.get(key)), String.class);
                            MedicationsHistoryNamesConverter converter = new MedicationsHistoryNamesConverter();
                            diffContents.put(fieldName, ListUtil.toList(converter.getConvertString(val1),converter.getConvertString(val2)));
                        } else if(StrUtil.equals("resectionSites",key)){
                            List<String> val1 = JSON.parseArray(StrUtil.toString(json1.get(key)), String.class);
                            List<String> val2 = JSON.parseArray(StrUtil.toString(json2.get(key)), String.class);
                            List<String> collect1 = val1.stream().map(item -> DictUtil.getLabel(item, dictParent.value())).collect(Collectors.toList());
                            List<String> collect2 = val2.stream().map(item -> DictUtil.getLabel(item, dictParent.value())).collect(Collectors.toList());
                            diffContents.put(fieldName, ListUtil.toList(CollUtil.join(collect1,"、"),CollUtil.join(collect2,"、")));
                        } else if(StrUtil.equals("materials",key)){
                            List<String> val1 = JSON.parseArray(StrUtil.toString(json1.get(key)), String.class);
                            List<String> val2 = JSON.parseArray(StrUtil.toString(json2.get(key)), String.class);
                            MaterialsConverter converter = new MaterialsConverter();
                            diffContents.put(fieldName, ListUtil.toList(converter.getConvertString(val1),converter.getConvertString(val2)));
                        } else if(isCustomerConverter){
                            String val1 = StrUtil.toString(json1.get(key));
                            String val2 = StrUtil.toString(json2.get(key));
                            // 调用@ExcelProperty中的converter定义类的getConvertString静态方法
                            try {
                                Class<?> converterClass = Class.forName(excelProperty.converter().getName());
                                Method method = converterClass.getMethod("getConvertString", String.class);
                                diffContents.put(fieldName, ListUtil.toList(method.invoke(null, val1),method.invoke(null, val2)));
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }else if(dateTimeFormat!=null){
                            diffContents.put(fieldName, ListUtil.toList(StrUtil.split(StrUtil.toString(json1.get(key))," ").get(0),
                                    StrUtil.split(StrUtil.toString(json2.get(key))," ").get(0)));
                        }else if(dictParent!=null){
                            diffContents.put(fieldName, ListUtil.toList(DictUtil.getLabel(StrUtil.toString(json1.get(key)),dictParent.value()),
                                    DictUtil.getLabel(StrUtil.toString(json2.get(key)),dictParent.value())));
                        }else{
                            diffContents.put(fieldName, ListUtil.toList(json1.get(key),json2.get(key)));
                        }
                    } catch (NoSuchFieldException e) {
                        // 如果找不到字段，使用原始键名
                        String baseKey = getByBaseKey(key);
                        diffContents.put(baseKey, ListUtil.toList(json1.get(key),json2.get(key)));
                    }
                }
            });

            return diffContents;
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }

    }

    private static String getByBaseKey(String fieldName) {
        String result = "";
        switch (fieldName){
            case "remark":
                result = "备注";
                break;
        }
        return result;
    }

}
